perm filename MIXER.SAI[T,LCS] blob sn#010300 filedate 1972-10-16 generic text, type T, neo UTF8
COMMENT ⊗   VALID 00005 PAGES 
RECORD PAGE   DESCRIPTION
 00001 00001
 00002 00002	BEGIN "MIXER"
 00005 00003	   PROCEDURE NEXT_OUTPUT_FILE
 00009 00004	  BEGIN "MAIN LOOP"
 00013 00005	Do actual mixing
 00015 ENDMK
⊗;
BEGIN "MIXER"

  COMMENT A program to edit sounds in digital form.
    Thanks go to Loren Rush and John Grey for there
    inspiration and suggestion;

  REQUIRE "⊂⊃⊂⊃" DELIMITERS;

  DEFINE BYTES_PER_WORD=2;
  DEFINE DSK_BLOCK_SIZE='200;

  DEFINE MAX_INPUT=10;
  DEFINE BUF_SIZE=DSK_BLOCK_SIZE;
  DEFINE OUT_SIZE=DSK_BLOCK_SIZE;
  DEFINE OUT_BLOCK_MAX=14*10;

  DEFINE MAX_CON='377777;

  INTEGER NUM_INPUTS,JUNK;
  INTEGER OUT_BLOCK,OUT_EOF,OUT_BLOCK_COUNT,OUT_COUNT,OUT_BYTE_POINTER,MAX_OUT;
  BOOLEAN DONE_FLAG;
  STRING OUT_FILE;

  REAL ARRAY GAIN[1:MAX_INPUT];
    COMMENT GAIN is what the samples are multiplied
      after begin normalized;

  INTEGER ARRAY MAX_AMP[1:MAX_INPUT];
    COMMENT MAX_AMP is the maximum amplitute, used to normalize
      the inputs;

  REAL ARRAY MULFACTOR[1:MAX_INPUT];
    COMMENT MULFACTOR=GAIN/MAX_AMPLITUDE;

  INTEGER ARRAY INTMULTIPLIER[1:MAX_INPUT];
    COMMENT Normalized integer multipier for samples;

  STRING ARRAY IN_FILE[1:MAX_INPUT];

COMMENT  INTEGER ARRAY USETI_POINTER[1:MAX_INPUT];
    COMMENT Indicates what's in core;

  INTEGER ARRAY BIGBUF[1:MAX_INPUT,1:BUF_SIZE];
    COMMENT Buffers for each input channel;

  INTEGER ARRAY OUT_BUF[1:OUT_SIZE];

  INTEGER ARRAY FIRST_BLOCK[1:MAX_INPUT];
    COMMENT First extension or block to use for each
      channel;
  INTEGER ARRAY BLOCK[1:MAX_INPUT];
    COMMENT Block currently being read from;

  INTEGER ARRAY LAST_BLOCK[1:MAX_INPUT];
    COMMENT Last extension or block to use for each
      channel;

  INTEGER ARRAY EOF[1:MAX_INPUT];
    COMMENT End of file status for each channel;

  SAFE INTEGER ARRAY BYTE_COUNT[1:MAX_INPUT];
  SAFE INTEGER ARRAY BYTE_POINTER[1:MAX_INPUT];

  DEFINE COMMA_TABLE=18;
   PROCEDURE NEXT_OUTPUT_FILE;
     BEGIN "NEXT_OUTPUT_FILE"
	    DEFINE CHANNEL=0;
	    STRING FILENAME;
	    ENTER(CHANNEL,FILENAME←OUT_FILE&"."&CVS(OUT_BLOCK←OUT_BLOCK+1),OUT_EOF);
	    IF OUT_EOF THEN
	      USERERR(0,0,"can't write "&FILENAME);
	    OUTSTR("Writing "&FILENAME&"
");
	    OUT_BLOCK_COUNT←0;
	    OUT_COUNT←BYTES_PER_WORD*BUF_SIZE;
	    OUT_BYTE_POINTER←POINT(18,OUT_BUF[1],-1);
	    END "NEXT_OUTPUT_FILE";

  PROCEDURE NEXT_BLOCK(INTEGER CHANNEL);
    IF CHANNEL≥1 THEN
      IF BLOCK[CHANNEL]≥LAST_BLOCK[CHANNEL] THEN BEGIN;
	  OUTSTR(IN_FILE[CHANNEL]&" finished
");
	  BYTE_COUNT[CHANNEL]←-1;
	  END
	ELSE BEGIN "DO_INPUT";
OUTCHR("↓");
	  IF ¬EOF[CHANNEL] THEN ARRYIN(CHANNEL,BIGBUF[CHANNEL,1],BUF_SIZE);
	  IF EOF[CHANNEL] THEN BEGIN "NEXT_INPUT_FILE"
	      STRING FILENAME;
	      LOOKUP(CHANNEL,FILENAME←IN_FILE[CHANNEL]&"."&CVS(BLOCK[CHANNEL]←
      BLOCK[CHANNEL]+1),EOF[CHANNEL]);
	      IF EOF[CHANNEL] THEN BEGIN;
		  OUTSTR(FILENAME&" not found, Set terminated
");
		  BYTE_COUNT[CHANNEL]←-1;
		  END
		ELSE BEGIN;
		  OUTSTR("Reading "&FILENAME&"
");
		  ARRYIN(CHANNEL,BIGBUF[CHANNEL,1],BUF_SIZE);
		  IF EOF[CHANNEL] THEN BEGIN
		      OUTSTR(FILENAME&" empty, Set terminated
");
		      BYTE_COUNT[CHANNEL]←-1;
		      END
		    ELSE BYTE_COUNT[CHANNEL]←BYTES_PER_WORD*BUF_SIZE;
		  END;
	      END "NEXT_INPUT_FILE"
	    ELSE BYTE_COUNT[CHANNEL]←BYTES_PER_WORD*BUF_SIZE;
	  BYTE_POINTER[CHANNEL]←POINT(18,BIGBUF[CHANNEL,1],-1);
	  END "DO_INPUT"
      ELSE BEGIN "DO_OUTPUT"
	INTEGER I;
OUTCHR("↑");
	DONE_FLAG←TRUE;
	FOR I←1 STEP 1 UNTIL NUM_INPUTS DO
	  IF BYTE_COUNT[I]≥0 THEN DONE_FLAG←FALSE;
	IF OUT_BLOCK_COUNT=OUT_BLOCK_MAX OR DONE_FLAG THEN QUICK_CODE
	    MOVE '13,MAX_OUT;
	    EXCH '13,@OUT_BYTE_POINTER;
	    MOVEM '13,I;
	    END;
	ARRYOUT(CHANNEL,OUT_BUF[1],OUT_SIZE);
	OUT_COUNT←BYTES_PER_WORD*BUF_SIZE;
	OUT_BYTE_POINTER←POINT(18,OUT_BUF[1],-1);
	IF OUT_BLOCK_COUNT=OUT_BLOCK_MAX AND ¬DONE_FLAG THEN BEGIN
	    OUT_BUF[1]←I;
	    OUT_COUNT←OUT_COUNT+BYTES_PER_WORD;
	    OUT_BYTE_POINTER←OUT_BYTE_POINTER+1;
	    END;
	IF OUT_BLOCK_COUNT≥OUT_BLOCK_MAX AND ¬DONE_FLAG THEN
	  NEXT_OUTPUT_FILE;
	OUT_BLOCK_COUNT←OUT_BLOCK_COUNT+1;
	END "DO_OUTPUT";
  BEGIN "MAIN LOOP"
    INTEGER I;
    REAL GAIN_SUM,MUL_SUM;
    STRING FILENAME;
    DONE_FLAG←FALSE;
    SETBREAK(COMMA_TABLE,","&'15," "&'12,"IOSN");
    OUTSTR("*** Digital Music Mixer ***
July 1972

");
    OUTSTR("Number of inputs=");
    NUM_INPUTS←CVD(INCHWL);
    IF NUM_INPUTS>MAX_INPUT THEN
      USERERR(0,0,"TOO MANY INPUTS");
    OUTSTR("File name, starting extension or block, ending extension or block:
");
    FOR I←1 STEP 1 UNTIL NUM_INPUTS DO BEGIN STRING FOO;
      INTEGER ARRAY INFOTAB[1:6];
      OUTSTR("#"&CVS(I)&"	");
      IN_FILE[I]←TTYINL(COMMA_TABLE,JUNK);
      FIRST_BLOCK[I]←CVD(TTYINS(COMMA_TABLE,JUNK));
      LAST_BLOCK[I]←CVD(INSTR('15));
      OPEN(I,"DSK",'17,0,0,JUNK,JUNK,EOF[I]←0);
      LOOKUP(I,FOO←IN_FILE[I]&"."&CVS(LAST_BLOCK[I]),EOF[I]);
      IF EOF[I] THEN USERERR(0,0,"CAN'T GET FILE: "&FOO);
      FILEINFO(INFOTAB);
      USETI(I,('1000000-INFOTAB[4])%('1000000*DSK_BLOCK_SIZE));
      ARRYIN(I,BIGBUF[I,1],DSK_BLOCK_SIZE);
      OUTSTR("Maximum amplitude="&CVS(MAX_AMP[I]←BIGBUF[I,DSK_BLOCK_SIZE])&"
");
      CLOSE(I);
      EOF[I]←TRUE;
      BYTE_COUNT[I]←0;
      END;
    OUTSTR("
Set gain for each input:
");
    FOR I←1 STEP 1 UNTIL NUM_INPUTS DO BEGIN STRING FOO;
      OUTSTR(CVS(I)&"  "&IN_FILE[I]&"  	");
      GAIN[I]←REALSCAN(FOO←INCHWL,'15);
      MULFACTOR[I]←GAIN[I]/MAX_AMP[I];
      BLOCK[I]←FIRST_BLOCK[I]-1;
      BYTE_COUNT[I]←0;
      END;
    OUTSTR("
Output file, Starting extension or block: 	");
    OUT_FILE←TTYINL(COMMA_TABLE,JUNK);
    OUT_BLOCK←CVD(INSTR('15))-1;
    OPEN(0,"DSK",'17,0,0,JUNK,JUNK,OUT_EOF←0);
    GAIN_SUM←0;
    FOR I←1 STEP 1 UNTIL NUM_INPUTS DO BEGIN
      MUL_SUM←MUL_SUM+MULFACTOR[I]*MAX_AMP[I];
      GAIN_SUM←GAIN_SUM+MULFACTOR[I];
      END;
    OUTSTR("Maximum output (default="&CVS(MAX_CON)&")	");
    IF (MAX_OUT←CVD(INCHWL))≤0 THEN
	MAX_OUT←MAX_CON
      ELSE IF MAX_OUT>'377777 THEN USERERR(0,0,"Maximum output limited to "&
	CVS(MAX_CON));
    OUTSTR("
Multipliers for each input:
   File  	Max. Amp % Gain		 Normalized gain
");
    FOR I←1 STEP 1 UNTIL NUM_INPUTS DO
      OUTSTR(CVS(I)&"  "&IN_FILE[I]&"  	"&CVS(MAX_AMP[I])&"	"&
CVG(MULFACTOR[I]/GAIN_SUM)&"	"&CVG(MULFACTOR[I]/MUL_SUM*MAX_OUT)&"
");
    OUTSTR("
");
    FOR I←1 STEP 1 UNTIL NUM_INPUTS DO
      INTMULTIPLIER[I]←MULFACTOR[I]/MUL_SUM*MAX_OUT*'400000;
    MAX_OUT←0;
    NEXT_OUTPUT_FILE;
COMMENT Do actual mixing;

    DO BEGIN INTEGER I,T;
	T←0;
	FOR I←1 STEP 1 UNTIL NUM_INPUTS DO
	    IF BYTE_COUNT[I]≥0 THEN BEGIN;
	      IF (BYTE_COUNT[I]←BYTE_COUNT[I]-1)≤0
		THEN NEXT_BLOCK(I);
COMMENT	      T←T+ILDB(BYTE_POINTER[I])*MULFACTOR[I];
	      QUICK_CODE
		MOVE '13,BYTE_POINTER;
		ADD '13,I;
		ILDB '13,-1('13);
		HRLZ '13,'13;	COMMENT Won't work for 12 bit!;
		MOVE '14,INTMULTIPLIER;
		ADD '14,I;
		MUL '13,-1('14);
		ADDM '13,T;
		END;
	      END;
	IDPB(T,OUT_BYTE_POINTER);
	IF ABS(T)>MAX_OUT THEN MAX_OUT←ABS(T);
	IF (OUT_COUNT←OUT_COUNT-1)≤0 THEN NEXT_BLOCK(0);
	END UNTIL DONE_FLAG;
    CLOSE(0);
    OUTSTR("


Output Maximum amplitude="&CVS(MAX_OUT));
    OUTSTR("

");
    END "MAIN LOOP";
  END "MIXER";